Les fichiers et les dossiers sont essentiels dans tous les programmes et Gtk possède beaucoup de composants pour faciliter leur manipulation. La sélection de fichiers et de dossiers par l'utilisateur est implémentée au travers de l'interface FileChooser. Il y a 4 modes de base pour le type FileChooserAction. Ses constructeurs sont:
FileChooserActionOpen
Utilisé pour permettre à l'utilisateur d'ouvrir un fichier.
FileChooserActionSave
Utilisé pour permettre à l'utilisateur de sauver un fichier.
FileChooserActionSelectFolder
Utilisé pour permettre à l'utilisateur de sélectionner un dossier.
FileChooserActionCreateFolder
Utilisé pour permettre à l'utilisateur de créer un dossier.
L'interface FileChooser a des attributs, des méthodes et des signaux mais ce n'est pas à proprement parler un widget. Il y a trois widgets qui utilisent l'interface de différentes manières: FileChooserWidget , FileChooserButton et FileChooserDialog. Comme vous le verrez dans l'exemple plus loin, un widget pour sauver un fichier ou sélectionner un dossier peut aussi contenir un bouton pour créer un dossier. Par conséquent, le constructeur FileActionCreateFolder ne sera probablement jamais utilisé dans vos programmes.
Il est important de noter que, bien que les widgets n'ouvrent pas et ne sauvent pas eux-mêmes les fichiers, la création des dossiers, au contraire, se fait par les widgets.
Notre premier exemple utilisera FileChooserWidget qui peut être dans le mode Ouvrir ou Sauver.
fileChooserWidgetNew :: FileChooserAction -> IO FileChooserWidget
On utilise FileChooserActionOpen ici, et quand l'utilisateur choisit un fichier en double-cliquant dessus ou en appuyant sur la touche Entrée, le signal onFileActived est émis. On utilise alors:
fileChooserGetFilename :: FileChooserClass self => self -> IO (Maybe FilePath)
A partir du chemin (FilePath), le programme peut alors ouvrir le fichier. Le format du chemin varie selon la plateforme et est déterminé par la variable d’environnement G_FILENAME_ENCODING.
Vous pouvez paramétrer si l'utilisateur peut sélectionner plusieurs fichiers ou non avec :
fileChooserSetselectMultiple :: FileChooserClass self => self -> Bool -> IO ()
et avec FileChooserWidget, vous pouvez facilement ajouter une case à cocher pour laisser l'utilisateur choisir. Placer un widget de ce type se fait avec:
fileChooserSetExtraWidget :: (FileChooserClass self, WidgetClass extraWidget)=> self -> extraWidget -> IO ()
Une autre fonctionnalité est l'utilisation de filtres pour afficher seulement les fichiers d'un certains type, soit en spécifiant leur type MIME, soit en spécifiant un motif, soit en spécifiant un format. Les filtres sont documentés dans Graphics.UI.Gtk.Selectors.FileFilter.
Le morceau de code qui suit montre l'utilisation des filtres. La dernière ligne ajoute les filtres dans le widget sélecteur de fichiers et, tout comme les widgets complémentaires, le placement se fait automatiquement.
hsfilt <- fileFilterNew
fileFilterAddPattern hsfilt "*.hs"
fileFilterSetName hsfilt "Haskell Source"
fileChooserAddFilter fch hsfilt
Vous pouvez également ajouter un widget de prévisualisation avec:
fileChooserSetPreviewWidget :: (FileChooserClass self, WidgetClass previewWidget) => self -> previewWidget -> IO ()
Dans l'exemple, ce widget est utilisé pour afficher les fichiers images. L'exemple utilise un widget Image (documenté dans Graphics.UI.Gtk.Display.Image) comme utilisé auparavant dans le chapitre 4.1. Nous avions utilisé alors imageNewFromFile pour ajouter des images sur un bouton; ici on construit un widget Image vide. Pour le mettre à jour, on utilise le signal onUpdatePreview qui est émis à chaque fois que l'utilisateur change sa sélection de fichier en bougeant la souris ou en appuyant sur les touches de raccourcis. Ce signal est plus général qu'il n'en a l'air, mais ici il n'est utilisé que pour la prévisualisation. Le bout de code est :
onUpdatePreview fch $
do file <- fileChooserGetPreviewFilename fch
case file of
Nothing -> putStrLn "No File Selected"
Just fpath -> imageSetFromFile img fpath
Il y a des fonctions et des attributs pour contrôler l'affichage; par exemple, ce qui se passe quand on sélectionne un fichier qui n'est pas un fichier graphique, mais elles ne sont pas strictement nécessaires. Dans l'exemple suivant, les fichiers non-graphiques sont simplement ignorés ou indiqués par une icône standard. Voilà a quoi tout cela ressemble:
Notez que l'utilisateur peut aussi ajouter et supprimer des marque-pages et que FileChooser possède également des fonctions pour les gérer. Mais cette fonctionnalité n'est pas abordée dans l'exemple qui suit:
import Graphics.UI.Gtk
main :: IO ()
main = do
initGUI
window <- windowNew
set window [windowTitle := "File Chooser Widget",
windowDefaultWidth := 500,
windowDefaultHeight := 400 ]
fch <- fileChooserWidgetNew FileChooserActionOpen
containerAdd window fch
selopt <- checkButtonNewWithLabel "Multiple File Selection"
fileChooserSetExtraWidget fch selopt
hsfilt <- fileFilterNew
fileFilterAddPattern hsfilt "*.hs"
fileFilterSetName hsfilt "Haskell Source"
fileChooserAddFilter fch hsfilt
nofilt <- fileFilterNew
fileFilterAddPattern nofilt "*.*"
fileFilterSetName nofilt "All Files"
fileChooserAddFilter fch nofilt
img <- imageNew
fileChooserSetPreviewWidget fch img
onUpdatePreview fch $
do file <- fileChooserGetPreviewFilename fch
case file of
Nothing -> putStrLn "No File Selected"
Just fpath -> imageSetFromFile img fpath
onFileActivated fch $
do dir <- fileChooserGetCurrentFolder fch
case dir of
Just dpath -> putStrLn
("The current directory is: " ++ dpath)
Nothing -> putStrLn "Nothing"
mul <- fileChooserGetSelectMultiple fch
if mul
then do
fls <- fileChooserGetFilenames fch
putStrLn
("You selected " ++ (show (length fls)) ++ "files:")
sequence_ (map putStrLn fls)
else do
file <- fileChooserGetFilename fch
case file of
Just fpath -> putStrLn ("You selected: " ++ fpath)
Nothing -> putStrLn "Nothing"
onToggled selopt $ do state <- toggleButtonGetActive selopt
fileChooserSetSelectMultiple fch state
widgetShowAll window
onDestroy window mainQuit
mainGUI
La seconde façon d'utiliser l'interface FileChooser est un bouton de sélection FileChooserButton.
fileChooserButtonNew :: String FileChooserAction -> String -> IO FileChooserButton
Le paramètre String est le nom du dialogue qui s'affiche quand l'utilisateur sélectionne l'option "Autre…" après avoir pressé sur le bouton. Dans l'exemple ci-dessous, on a construit un bouton sélecteur de fichiers avec FileChooserActionSelectFolder. Voici a quoi ressemble le bouton après avoir sélectionné le répertoire "Test".
Voici a quoi ressemble le dialogue:
Comme on peut le voir, il y a un bouton "créer un dossier" en haut à droite de la fenêtre de dialogue et il peut être utilisé pour créer un nouveau dossier. Voici ce qui arrive quand on essaie de créer un dossier déjà existant:
Créer ou recréer un dossier déjà existant peut causer des problèmes, c'est pour cette raison que Gtk2Hs se charge d'avertir automatiquement l'utilisateur. Quand l'utilisateur sélectionne un répertoire existant, le signal onCurrentFolderChanged est émit et le programme peut lancer l'action appropriée. Créer un dossier le sélectionne automatiquement, on peut donc utiliser onCurrentFolderChanged pour travailler sur ce dossier. Voici un petit exemple:
import Graphics.UI.Gtk
main :: IO ()
main = do
initGUI
window <- windowNew
set window [windowTitle := "File Chooser Button",
windowDefaultWidth := 250, windowDefaultHeight := 75 ]
fchd <- fileChooserButtonNew "Select Folder"
FileChooserActionSelectFolder
containerAdd window fchd
onCurrentFolderChanged fchd $
do dir <- fileChooserGetCurrentFolder fchd
case dir of
Nothing -> putStrLn "Nothing"
Just dpath -> putStrLn ("You selected:\n" ++ dpath)
widgetShowAll window
onDestroy window mainQuit
mainGUI
La troisième manière d'utiliser une interface FileChooser se fait avec un FileChooserDialog. Elle peut être construite en mode ouvrir ou sauver et est habituellement lancée depuis un menu ou une barre d'outils.
FileChooserDialog implémente à la fois FileChooser et Dialog. Rappelons (chapitre 4.5) qu'un dialogue est un widget composite avec des boutons généralement implémentés avec dialogRun qui produit des sorties de type ResponseId. FileChooserDialog est construit avec:
fileChooserDialogNew ::
Maybe String -- title of the dialog or default
-> Maybe Window -- parent window of the dialog or nothing
-> FileChooserAction -- open or save mode
-> [(String, ResponseId)] -- list of buttons and their response codes
-> IO FileChooserDialog
Tout ce que l'on a faire est de spécifier les noms des boutons et leurs sorties (ResponseId) dans le quatrième argument et ils seront implémentés automatiquement.
L'exemple lance un widget FileChooserActionSave et ce dialogue possède trois boutons. Voici a quoi il ressemble:
Comme vous pouvez le voir, il y a un bouton en haut à droite pour créer un dossier. Comme dans l'exemple précédent, tenter de créer un dossier déjà existant entraîne un message d'erreur. Toutefois, on peut réécrire sur un fichier (autorisé par défaut). Vous pouvez faire confirmer la réécriture d'un fichier par l'utilisateur avec:
fileChooserSetDoOverwriteconfirmation :: FileChooserClass self => self -> Bool -> IO ()
Comme expliqué auparavant, ni enregistrement, ni écriture n'est faite par le widget FileChooserDialog; le programme obtient seulement le chemin d'accès
Voici le code du troisième exemple:
import Graphics.UI.Gtk
main :: IO ()
main = do
initGUI
fchdal <- fileChooserDialogNew (Just "Save As...Dialog") Nothing
FileChooserActionSave
[("Cancel", ResponseCancel),
("Save", ResponseAccept),
("Backup", ResponseUser 100)]
fileChooserSetDoOverwriteConfirmation fchdal True
widgetShow fchdal
response <- dialogRun fchdal
case response of
ResponseCancel -> putStrLn "You cancelled..."
ResponseAccept -> do nwf <- fileChooserGetFilename fchdal
case nwf of
Nothing -> putStrLn "Nothing"
Just path -> putStrLn ("New file path is:\n" ++ path)
ResponseUser 100 -> putStrLn "You pressed the backup button"
ResponseDeleteEvent -> putStrLn "You closed the dialog window..."
widgetDestroy fchdal
onDestroy fchdal mainQuit
mainGUI